S.Node.Expander = function (option) {
    let me = this;
    Q.doSuperConstructor(me, S.Node.Expander, ['+']);
    me.setOption(me.option);
    me.setOption(option);
};

S.Node.Expander.prototype = {
    xtype: 'expander',
    expanded: false,
    option: {
        zIndex: 3,
        movable: false,
        selectable: false,
        style: {
            alpha: 1,
            label: {
                color: '#fff',
                size: {
                    width: 17,
                    height: 17
                },
                align: {
                    position: 'CENTER_MIDDLE'
                },
                border: {
                    width: 1,
                    radius: 0,
                    color: '#fff'
                },
                padding: 0,
                position: 'LEFT_MIDDLE',
                anchor: {
                    position: 'LEFT_MIDDLE'
                },
                font: {
                    size: 13
                }
            }
        }
    },

    setExpanded: function (value) {
        let me = this;
        if (value) {
            me.expand();
        } else {
            me.collapse();
        }
        me.parent.expanded = me.expanded = value;
        me.name = value ? '-' : '+';
    },

    setOption: function (option) {
        let me = this;
        S.setOption(me, option);
    },

    onClick: function (evt) {
        evt.getData().click();
    },

    click: function () {
        let me = this;
        me.setExpanded(!me.expanded);
    },

    expand: function () {
        let me = this, g = me.graph, instance = me.parent, root = instance.parent;
        let froms = instance.removeEdgesNotMine();
        g.createChildren(instance, root ? {top: 0, left: 0} : g.node.padding, root != null);
        me.createEdges(froms);
        me.createEdges(instance.children.datas);
        if (root) {
            let offset = me.offset();
            me.moveChildren(instance, root.children.datas, offset);
            g.createFrame(root);
        } else {
            g.createFrame(instance);
        }
        g.fireEvent('onexpanded', me);
    },

    createEdges: function (nodes) {
        let g = this.graph;
        for (let node of nodes) {
            if (node.xtype == 'instance') {
                g.createEdges(node.data.relations, node.data.children);
            }
        }
    },

    collapse: function () {
        let me = this, g = me.graph, instance = me.parent, root = instance.parent, offset = -me.offset();
        let froms = instance.childrenEdgeFroms();
        instance.removeChildren();
        if (root) {
            me.moveChildren(instance, root.children.datas, offset);
            g.createFrame(root);
        }
        me.createEdges(froms);
        g.createEdges(instance.data.relations, instance.data.children);
        g.fireEvent('oncollapsed', me);
    },

    offset: function (expanded) {
        let me = this, count = me.parent.childrenCount - 1;
        return count > 0 ? me.parent.children.datas[1].styles['label.size'].height * count : 0;
    },

    moveChildren: function (instance, children, offset) {
        let me = this;
        for (let child of children) {
            if (instance.id != child.id && instance.y < child.y) {
                child.y += offset;
                if (child.childrenCount > 0) {
                    me.moveChildren(instance, child.children.datas, offset);
                }
            }
        }
    }
};

Q.extend(S.Node.Expander, Q.Text);